gdk/x11: Implement XI2.4 touchpad gesture support
authorPovilas Kanapickas <povilas@radix.lt>
Sun, 5 Sep 2021 22:32:16 +0000 (01:32 +0300)
committerPovilas Kanapickas <povilas@radix.lt>
Mon, 27 Sep 2021 20:19:33 +0000 (23:19 +0300)
gdk/gdkseatdefault.c
gdk/x11/gdkdevice-xi2.c
gdk/x11/gdkdevicemanager-x11.c
gdk/x11/gdkdevicemanager-xi2.c
gdk/x11/gdkprivate-x11.h
meson.build

index ce47df8230e3f5c16a10ab0ee060f8e0f3aa6c83..18d44662ec1e1472ddc14195c7f85cd66c38e971 100644 (file)
@@ -43,7 +43,8 @@ struct _GdkSeatDefaultPrivate
                          GDK_ENTER_NOTIFY_MASK |                        \
                          GDK_LEAVE_NOTIFY_MASK |                        \
                          GDK_PROXIMITY_IN_MASK |                        \
-                         GDK_PROXIMITY_OUT_MASK)
+                         GDK_PROXIMITY_OUT_MASK |                       \
+                         GDK_TOUCHPAD_GESTURE_MASK)
 
 G_DEFINE_TYPE_WITH_PRIVATE (GdkSeatDefault, gdk_seat_default, GDK_TYPE_SEAT)
 
index 5976dfafc486dcdb9f47b39a85bd37c77f95dcee..7062a7330a9a50675bb2beca4c77f003c4c58f17 100644 (file)
@@ -619,6 +619,20 @@ _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager
     }
 #endif /* XINPUT_2_2 */
 
+#ifdef XINPUT_2_4
+  /* XInput 2.4 includes touchpad gesture support */
+  if (minor >= 4 &&
+      event_mask & GDK_TOUCHPAD_GESTURE_MASK)
+    {
+      XISetMask (mask, XI_GesturePinchBegin);
+      XISetMask (mask, XI_GesturePinchUpdate);
+      XISetMask (mask, XI_GesturePinchEnd);
+      XISetMask (mask, XI_GestureSwipeBegin);
+      XISetMask (mask, XI_GestureSwipeUpdate);
+      XISetMask (mask, XI_GestureSwipeEnd);
+    }
+#endif
+
   return mask;
 }
 
@@ -667,6 +681,36 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
   return state;
 }
 
+#ifdef XINPUT_2_4
+guint
+_gdk_x11_device_xi2_gesture_type_to_phase (int evtype, int flags)
+{
+  switch (evtype)
+    {
+    case XI_GesturePinchBegin:
+    case XI_GestureSwipeBegin:
+      return GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
+
+    case XI_GesturePinchUpdate:
+    case XI_GestureSwipeUpdate:
+      return GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
+
+    case XI_GesturePinchEnd:
+      if (flags & XIGesturePinchEventCancelled)
+        return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
+      return GDK_TOUCHPAD_GESTURE_PHASE_END;
+
+    case XI_GestureSwipeEnd:
+      if (flags & XIGestureSwipeEventCancelled)
+        return GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
+      return GDK_TOUCHPAD_GESTURE_PHASE_END;
+    default:
+      g_assert_not_reached ();
+      return GDK_TOUCHPAD_GESTURE_PHASE_END;
+    }
+}
+#endif /* XINPUT_2_4 */
+
 void
 _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2    *device,
                                          guint               n_valuator,
index d01a5db24bbad88e6a97cdf09622645ef704b797..27a7d2007bc2e53b489320943e524284d0b21d2f 100644 (file)
@@ -41,7 +41,7 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
       int major, minor;
 
       major = 2;
-      minor = 3;
+      minor = 4;
 
       if (XIQueryVersion (xdisplay, &major, &minor) != BadRequest)
         {
index e4114e52796ae99ce504f016fa3df7c795870c21..9eb4e9bc560ade9247be92659263b14f45ddc861 100644 (file)
@@ -1275,6 +1275,26 @@ get_event_surface (GdkEventTranslator *translator,
           }
       }
       break;
+#ifdef XINPUT_2_4
+    case XI_GesturePinchBegin:
+    case XI_GesturePinchUpdate:
+    case XI_GesturePinchEnd:
+      {
+        XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev;
+
+        surface = gdk_x11_surface_lookup_for_display (display, xev->event);
+      }
+      break;
+    case XI_GestureSwipeBegin:
+    case XI_GestureSwipeUpdate:
+    case XI_GestureSwipeEnd:
+      {
+        XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev;
+
+        surface = gdk_x11_surface_lookup_for_display (display, xev->event);
+      }
+      break;
+#endif /* XINPUT_2_4 */
     case XI_Enter:
     case XI_Leave:
     case XI_FocusIn:
@@ -1881,6 +1901,126 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
       break;
 #endif  /* XINPUT_2_2 */
 
+#ifdef XINPUT_2_4
+    case XI_GesturePinchBegin:
+    case XI_GesturePinchUpdate:
+    case XI_GesturePinchEnd:
+      {
+        XIGesturePinchEvent *xev = (XIGesturePinchEvent *) ev;
+        GdkModifierType state;
+        GdkTouchpadGesturePhase phase;
+        double x, y;
+
+#ifdef G_ENABLE_DEBUG
+        const char *event_name = "";
+        switch (xev->evtype)
+          {
+          case XI_GesturePinchBegin:
+            event_name = "begin";
+            break;
+          case XI_GesturePinchUpdate:
+            event_name = "update";
+            break;
+          case XI_GesturePinchEnd:
+            event_name = "end";
+            break;
+          default:
+            break;
+          }
+#endif
+
+        GDK_NOTE (EVENTS,
+                  g_message ("pinch gesture %s:\twindow %ld\n\tfinger_count: %u%s",
+                             event_name,
+                             xev->event,
+                             xev->detail,
+                             xev->flags & XIGesturePinchEventCancelled ? "\n\tcancelled" : ""));
+
+        device = g_hash_table_lookup (device_manager->id_table,
+                                      GINT_TO_POINTER (xev->deviceid));
+
+        state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group);
+        phase = _gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags);
+
+        x = (double) xev->event_x / scale;
+        y = (double) xev->event_y / scale;
+
+        event = gdk_touchpad_event_new_pinch (surface,
+                                              device,
+                                              xev->time,
+                                              state,
+                                              phase,
+                                              x, y,
+                                              xev->detail,
+                                              xev->delta_x,
+                                              xev->delta_y,
+                                              xev->scale,
+                                              xev->delta_angle * G_PI / 180);
+
+        if (ev->evtype == XI_GesturePinchBegin)
+          set_user_time (event);
+      }
+      break;
+
+    case XI_GestureSwipeBegin:
+    case XI_GestureSwipeUpdate:
+    case XI_GestureSwipeEnd:
+      {
+        XIGestureSwipeEvent *xev = (XIGestureSwipeEvent *) ev;
+        GdkModifierType state;
+        GdkTouchpadGesturePhase phase;
+        double x, y;
+
+#ifdef G_ENABLE_DEBUG
+        const char *event_name = "";
+        switch (xev->evtype)
+          {
+          case XI_GestureSwipeBegin:
+            event_name = "begin";
+            break;
+          case XI_GestureSwipeUpdate:
+            event_name = "update";
+            break;
+          case XI_GestureSwipeEnd:
+            event_name = "end";
+            break;
+          default:
+            break;
+          }
+#endif
+
+        GDK_NOTE (EVENTS,
+                  g_message ("swipe gesture %s:\twindow %ld\n\tfinger_count: %u%s",
+                             event_name,
+                             xev->event,
+                             xev->detail,
+                             xev->flags & XIGestureSwipeEventCancelled ? "\n\tcancelled" : ""));
+
+        device = g_hash_table_lookup (device_manager->id_table,
+                                      GINT_TO_POINTER (xev->deviceid));
+
+        state = _gdk_x11_device_xi2_translate_state (&xev->mods, NULL, &xev->group);
+        phase = _gdk_x11_device_xi2_gesture_type_to_phase (xev->evtype, xev->flags);
+
+        x = (double) xev->event_x / scale;
+        y = (double) xev->event_y / scale;
+
+        event = gdk_touchpad_event_new_swipe (surface,
+                                              device,
+                                              xev->time,
+                                              state,
+                                              phase,
+                                              x, y,
+                                              xev->detail,
+                                              xev->delta_x,
+                                              xev->delta_y);
+
+        if (ev->evtype == XI_GestureSwipeBegin)
+          set_user_time (event);
+      }
+      break;
+#endif /* XINPUT_2_4 */
+
     case XI_Enter:
     case XI_Leave:
       {
@@ -1992,7 +2132,8 @@ gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
           GDK_BUTTON3_MOTION_MASK |
           GDK_BUTTON_MOTION_MASK |
           GDK_FOCUS_CHANGE_MASK |
-          GDK_TOUCH_MASK);
+          GDK_TOUCH_MASK |
+          GDK_TOUCHPAD_GESTURE_MASK);
 }
 
 static void
index 4461f15e6b3a3ad7315dcab3a09f43ace73d1d28..74a5155096641c2abbfd75af1cf0460a686c3dfc 100644 (file)
@@ -140,6 +140,7 @@ guchar * _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *devic
 guint    _gdk_x11_device_xi2_translate_state      (XIModifierState *mods_state,
                                                    XIButtonState   *buttons_state,
                                                    XIGroupState    *group_state);
+guint _gdk_x11_device_xi2_gesture_type_to_phase (int evtype, int flags);
 int      _gdk_x11_device_xi2_get_id               (GdkX11DeviceXI2 *device);
 void     _gdk_device_xi2_unset_scroll_valuators   (GdkX11DeviceXI2 *device);
 
index e85daf88f5b7d69b27e3b4cd4c3c4252b37ceae4..0965a2f113bf6de1a8da7086d981cb62474f66e2 100644 (file)
@@ -557,6 +557,13 @@ if x11_enabled
   endif
   cdata.set('XINPUT_2_2', 1)
 
+  has_gesture_pinch_event = cc.has_member('XIGesturePinchEvent', 'type', dependencies: xi_dep,
+                                          prefix: '''#include <X11/Xlib.h>
+                                                     #include <X11/extensions/XInput2.h>''')
+  if has_gesture_pinch_event
+    cdata.set('XINPUT_2_4', 1)
+  endif
+
   xinerama_dep = dependency('xinerama')
   if not cc.has_header_symbol('X11/extensions/Xinerama.h', 'XineramaQueryExtension', dependencies: xinerama_dep)
     error('X11 backend enabled, but Xinerama extension does not work.')